package com.run.go.gearbox.core.gearbox;

import com.run.go.gearbox.core.gearbox.gear.Gear;
import sun.misc.Unsafe;

import java.lang.reflect.Field;

public abstract class AbstractGearbox implements Gearbox {


    protected static final Unsafe U;

    protected static final long CURRENT_GEAR_NUM;

    static {
        try {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            U = (Unsafe) field.get(null);
            Class<?> k = AbstractGearbox.class;
            CURRENT_GEAR_NUM = U.objectFieldOffset(k.getDeclaredField("currentGearNum"));
        } catch (Exception e) {
            throw new Error(e);
        }
    }

    /* 齿轮组  */
    protected volatile Gear[] gears = null;

    /**
     * 当前档位
     */
    protected volatile Integer currentGearNum = 0;

    /**
     * 最高档位
     */
    protected Integer gearNum;

    /**
     * 但齿轮马力
     */
    protected Integer power;

    protected Integer powerChain;



    protected abstract Gear newGear();

    @Override
    public void gear() {
        System.out.println("升档");
        if(currentGearNum.compareTo(gearNum) >=0){
            /* 已经是高档位了 别超速了 安全第一 */
            return;
        }
        Gear [] newGears = new Gear[gears.length + 1];
        Gear gear = newGear();
        gear.start();

        for (int i = 0; i < gears.length; i++) {
            newGears[i] = gears[i];
        }
        newGears[gears.length] = gear;
        this.gears = newGears;
        U.compareAndSwapObject(this, CURRENT_GEAR_NUM, currentGearNum, currentGearNum + 1 );
    }


    @Override
    public void downGear() {

        System.out.println("降档 剩余马力：" + surplusPower());

        /* 如果变速箱剩余马力 小于一个档位不降档 */
        if(surplusPower() < power){
            return;
        }

        if(currentGearNum.compareTo(1) <=0){
            /* 已经是最低档位了 */
            return;
        }

        Gear [] newGears = new Gear[gears.length - 1];
        for (int i = 0; i < newGears.length; i++) {
            newGears[i] = gears[i];
        }
        U.compareAndSwapObject(this, CURRENT_GEAR_NUM, currentGearNum, currentGearNum - 1 );
        Gear stopGeat = gears[newGears.length];
        this.gears = newGears;
        stopGeat.stop();
    }

    @Override
    public int surplusPower() {
        Integer surplusPower = 0;
        for (Gear gear : gears) {
            surplusPower += gear.surplusPower();
        }
        return surplusPower;
    }

    @Override
    public void start() {
        for (Gear gear: gears) {
            gear.start();
        }
    }

    @Override
    public void stop() {
        for (Gear gear: gears) {
            gear.stop();
        }
    }


    public Integer getPower() {
        return power;
    }

    public void setPower(Integer power) {
        this.power = power;
    }

    public Gear[] getGears() {
        return gears;
    }


    public Integer getCurrentGearNum() {
        return currentGearNum;
    }

    public void setCurrentGearNum(Integer currentGearNum) {
        this.currentGearNum = currentGearNum;
    }

    public Integer getGearNum() {
        return gearNum;
    }

    public void setGearNum(Integer gearNum) {
        this.gearNum = gearNum;
    }

    public Integer getPowerChain() {
        return powerChain;
    }

    public void setPowerChain(Integer powerChain) {
        this.powerChain = powerChain;
    }
}
